import { diffLines, diffChars, createPatch, applyPatch } from 'diff';
import { createHash } from 'crypto';

/**
 * Diff 工具类
 * 用于生成和应用文件差异
 */
export class DiffUtils {
  /**
   * 生成文件差异
   * @param oldContent 旧内容
   * @param newContent 新内容
   * @param filename 文件名（用于生成 patch header）
   * @returns diff 字符串
   */
  static generateDiff(oldContent: string, newContent: string, filename: string = 'file'): string {
    // 使用 unified diff 格式
    const patch = createPatch(filename, oldContent, newContent, 'old', 'new');
    return patch;
  }

  /**
   * 应用差异到内容
   * @param baseContent 基础内容
   * @param diffContent diff 内容
   * @returns 应用差异后的内容
   */
  static applyDiff(baseContent: string, diffContent: string): string {
    try {
      const result = applyPatch(baseContent, diffContent);
      if (result === false) {
        throw new Error('Failed to apply patch');
      }
      return result;
    } catch (error) {
      console.error('[DiffUtils] 应用差异失败:', error);
      throw error;
    }
  }

  /**
   * 计算内容哈希
   * @param content 内容
   * @returns MD5 哈希值
   */
  static calculateHash(content: string): string {
    return createHash('md5').update(content, 'utf8').digest('hex');
  }

  /**
   * 获取差异统计信息
   * @param oldContent 旧内容
   * @param newContent 新内容
   * @returns 统计信息
   */
  static getChangeStats(oldContent: string, newContent: string): {
    linesAdded: number;
    linesDeleted: number;
    linesModified: number;
  } {
    const diff = diffLines(oldContent, newContent);
    
    let linesAdded = 0;
    let linesDeleted = 0;
    let linesModified = 0;

    diff.forEach(part => {
      if (part.added) {
        linesAdded += part.count || 0;
      } else if (part.removed) {
        linesDeleted += part.count || 0;
      }
    });

    // 简单估算修改行数
    linesModified = Math.min(linesAdded, linesDeleted);
    linesAdded -= linesModified;
    linesDeleted -= linesModified;

    return { linesAdded, linesDeleted, linesModified };
  }

  /**
   * 检查差异大小是否合理
   * @param diffContent diff 内容
   * @param maxSize 最大允许大小（字节）
   * @returns 是否合理
   */
  static isDiffSizeReasonable(diffContent: string, maxSize: number = 1024 * 1024): boolean {
    return Buffer.byteLength(diffContent, 'utf8') <= maxSize;
  }

  /**
   * 压缩差异内容（如果需要）
   * @param diffContent diff 内容
   * @returns 压缩后的内容
   */
  static compressDiff(diffContent: string): string {
    // 简单的压缩：移除多余的空白行
    return diffContent
      .split('\n')
      .filter((line, index, array) => {
        // 保留非空行和有意义的空行
        if (line.trim() !== '') return true;
        // 避免连续的空行
        return index === 0 || index === array.length - 1 || array[index - 1].trim() !== '';
      })
      .join('\n');
  }
}

/**
 * 差异类型定义
 */
export interface FileDiff {
  type: 'unified-diff';
  filename: string;
  oldHash: string;
  newHash: string;
  patch: string;
  stats: {
    linesAdded: number;
    linesDeleted: number;
    linesModified: number;
  };
}

/**
 * 创建完整的文件差异对象
 * @param oldContent 旧内容
 * @param newContent 新内容
 * @param filename 文件名
 * @returns 差异对象
 */
export function createFileDiff(oldContent: string, newContent: string, filename: string): FileDiff {
  const patch = DiffUtils.generateDiff(oldContent, newContent, filename);
  const stats = DiffUtils.getChangeStats(oldContent, newContent);
  
  return {
    type: 'unified-diff',
    filename,
    oldHash: DiffUtils.calculateHash(oldContent),
    newHash: DiffUtils.calculateHash(newContent),
    patch,
    stats
  };
}
